package com.joinval.common.utils;

import com.joinval.common.exception.JoinvalException;
import com.joinval.modules.joinval.dto.RequestLimitDTO;
import lombok.var;
import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 定义一个切面类，用于处理请求频率限制
 *
 * @author shen shuai
 * @create 2024-09-29 上午 10:08
 */
@Aspect
@Component
@Order(1)
public class RequestLimitAspect {

    ConcurrentHashMap<String, ConcurrentHashMap<String, Integer>> dailyCounts = new ConcurrentHashMap<>();
    ConcurrentHashMap<String, ExpiringMap<String, Integer>> expiringMaps = new ConcurrentHashMap<>();

    /**
     * 定义切点
     * 让所有标注@LimitRequest注解的方法都执行切面方法
     *
     * @param requestLimit 注解
     */
    @Pointcut("@annotation(requestLimit)")
    public void excudeService(RequestLimit requestLimit) {

    }

    /**
     * @param proceedingJoinPoint 切面方法
     * @param requestLimit        注解
     */
    @Around("excudeService(requestLimit)")
    public Result doAround(ProceedingJoinPoint proceedingJoinPoint, RequestLimit requestLimit) throws Throwable {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (Objects.isNull(servletRequestAttributes)) {
            return Result.error("请求异常");
        }

        HttpServletRequest request = servletRequestAttributes.getRequest();
        String requestURI = request.getRequestURI();
        String remoteAddr = request.getRemoteAddr();

        // 检查日调用次数
        ConcurrentHashMap<String, Integer> uriDailyCounts = dailyCounts.getOrDefault(requestURI, new ConcurrentHashMap<>());
        int dailyCount = uriDailyCounts.getOrDefault(remoteAddr, 0);
        if (dailyCount >= requestLimit.dailyLimit()) {
            return Result.error("今日请求已达上限");
        }

        // 更新日调用次数
        uriDailyCounts.put(remoteAddr, dailyCount + 1);
        dailyCounts.put(requestURI, uriDailyCounts);

        // 检查频率限制
        ExpiringMap<String, Integer> expiringMap = expiringMaps.getOrDefault(requestURI, ExpiringMap.builder().variableExpiration().build());
        Integer requestCount = expiringMap.getOrDefault(remoteAddr, 0);
        if (requestCount >= requestLimit.count()) {
            return Result.error("请求频率太快啦~~");
        }

        // 更新频率计数
        if (requestCount == 0) {
            expiringMap.put(remoteAddr, requestCount + 1, ExpirationPolicy.CREATED, requestLimit.time(), TimeUnit.MILLISECONDS);
        } else {
            expiringMap.put(remoteAddr, requestCount + 1);
        }

        expiringMaps.put(requestURI, expiringMap);

        // 执行目标方法
        Object result = proceedingJoinPoint.proceed();
        return Result.ok().data(result);
    }


}
